using System;
using System.Collections.Generic;
using UnityEngine;

namespace abilities.parameters
{
    public delegate void ParameterChangedCallBack(ParameterEntry parameterEntry,ParameterValue parameterValue);

    public class ParameterChangeSignal
    {
        //检查两次订阅
        struct SignalStruct
        {
            public ParameterChangedCallBack ListenerMethod;
            public ParameterEntry ParameterEntry;
        };

        struct DelayedStruct
        {
            public ParameterValue parameterValue;
            public ParameterEntry ParameterEntry;
        };

        List<SignalStruct> _listeners = new();
        bool _isDispatching; //会存在调用中调用
        bool _isDestroyed;
        private List<SignalStruct> _scheduledRemovedListeners = new();
        private List<DelayedStruct> _scheduledDispatches = new();

        public ParameterChangeSignal()
        {
            _isDestroyed = false;
            _isDispatching = false;
        }

        ~ParameterChangeSignal()
        {
            RemoveAllListeners();
            _isDestroyed = true;
        }

        public void Dispatch(ParameterEntry parameterEntry,ParameterValue parameterValue)
        {
            if (_isDispatching)
            {
                foreach (var iter in _scheduledDispatches)
                {
                    if (iter.parameterValue == parameterValue && iter.ParameterEntry == parameterEntry)
                    {
                        return;
                    }
                }

                _scheduledDispatches.Add(new DelayedStruct
                    { parameterValue = parameterValue, ParameterEntry = parameterEntry });
                return;
            }

            if (_listeners.Count < 1)
            {
                return;
            }

            _isDispatching = true;
            foreach (var listenerStruct in _listeners)
            {
                if (listenerStruct.ParameterEntry != null && parameterEntry == listenerStruct.ParameterEntry)
                    listenerStruct.ListenerMethod(parameterEntry, parameterValue);
                if (_isDestroyed)
                    return;
            }

            _isDispatching = false;
            if (_scheduledRemovedListeners.Count > 0)
            {
                foreach (var listenerStruct in _scheduledRemovedListeners)
                {
                    if (listenerStruct.ParameterEntry == null)
                    {
                        RemoveListener(listenerStruct.ListenerMethod);
                        break;
                    }
                    else
                        RemoveListener(listenerStruct.ParameterEntry, listenerStruct.ListenerMethod);
                }

                _scheduledRemovedListeners = new();
            }

            if (_scheduledDispatches.Count > 0)
            {
                List<DelayedStruct> dispatches = _scheduledDispatches;
                _scheduledDispatches = new();
                foreach (var toDispatch in dispatches)
                {
                    Dispatch(toDispatch.ParameterEntry, toDispatch.parameterValue);
                }
            }
        }

        /// <summary>
        /// 添加对应入口的订阅
        /// </summary>
        /// <param name="parameterEntry"></param>
        /// <param name="listenerMethod"></param>
        public void AddListener(ParameterEntry parameterEntry, ParameterChangedCallBack listenerMethod)
        {
            if (listenerMethod == null || parameterEntry == null)
                throw new NotImplementedException(
                    $"AddListener listener null not allow; ParameterEntity:{parameterEntry},listenerMethod:{listenerMethod}");

            if (HasListener(listenerMethod))
            {
                Debug.LogError("AddListener listener already exists");
                return;
            }

            if (_isDispatching)
            {
                _listeners = new List<SignalStruct>(_listeners);
            }

            _listeners.Add(new SignalStruct { ListenerMethod = listenerMethod, ParameterEntry = parameterEntry });
        }

        /// <summary>
        /// 取消该方法对应入口的订阅
        /// </summary>
        /// <param name="parameterEntry"></param>
        /// <param name="listenerMethod"></param>
        public void RemoveListener(ParameterEntry parameterEntry, ParameterChangedCallBack listenerMethod)
        {
            if (_listeners.Count < 1)
                return;
            if (listenerMethod == null || parameterEntry == null)
                throw new NotImplementedException($"ParameterEntity:{parameterEntry},listenerMethod:{listenerMethod}");

            if (_isDispatching)
            {
                _scheduledRemovedListeners.Add(new SignalStruct
                    { ListenerMethod = listenerMethod, ParameterEntry = parameterEntry });
                return;
            }

            for (int i = _listeners.Count; i >= 0; i--)
            {
                var listener = _listeners[i];
                if (listener.ParameterEntry == parameterEntry && listener.ListenerMethod == listenerMethod)
                {
                    _listeners.Remove(listener);
                    break;
                }
            }
        }

        /// <summary>
        /// 取消所有该方法的订阅
        /// </summary>
        /// <param name="listenerMethod"></param>
        public void RemoveListener(ParameterChangedCallBack listenerMethod)
        {
            if (_listeners.Count < 1)
                return;
            if (listenerMethod == null)
                throw new NotImplementedException($"listenerMethod:{listenerMethod}");

            if (_isDispatching)
            {
                _scheduledRemovedListeners.Add(new SignalStruct
                    { ListenerMethod = listenerMethod, ParameterEntry = null });
                return;
            }

            for (int i = _listeners.Count; i >= 0; i--)
            {
                var listener = _listeners[i];
                if (listener.ListenerMethod == listenerMethod)
                {
                    _listeners.Remove(listener);
                }
            }
        }

        public void RemoveAllListeners()
        {
            if (_isDispatching)
                _listeners = new();
            else
                _listeners.Clear();
        }

        bool HasListener(ParameterChangedCallBack listenerMethod)
        {
            foreach (var listenersIterator in _listeners)
            {
                if (listenersIterator.ListenerMethod == listenerMethod)
                {
                    return true;
                }
            }

            return false;
        }
    }
}